#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <memory>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Com_ERR.hpp"
#include "Log.hpp"
#include "Inet_Addr.hpp"

namespace Socket_ns
{
    using namespace LogModule;
    const static int g_blcklog = 8; // 全连接队列的长度

    class Socket;                             // 前置声明
    using SockSPtr = std::shared_ptr<Socket>; // 定义一个 Socket 类型

    class Socket
    {
    public:
        virtual void CreateSocket() = 0;                                         // 创建套接字
        virtual void CreateBind(uint16_t port) = 0;                              // 绑定
        virtual void CreateListen(int blcklog = g_blcklog) = 0;                  // 监听
        virtual SockSPtr Accepter(Inet_Addr *client) = 0;                        // 连接
        virtual bool Connector(std::string server_ip, uint16_t server_port) = 0; // 获取连接

        virtual int Sockfd() = 0; // 获取 socket
        virtual void Close() = 0; // 关闭 socket

        virtual ssize_t Recv(std::string *out) = 0;      // 发送消息
        virtual ssize_t Send(const std::string &in) = 0; // 接收消息
    public:
        void BuildListenSocket(uint16_t port) // TCP 服务端 创建、绑定、监听
        {
            CreateSocket();
            CreateBind(port);
            CreateListen();
        }

        bool BuildClientSoket(const std::string &server_ip, uint16_t server_port) //  TCP 客户端获取连接
        {
            CreateSocket();
            return Connector(server_ip, server_port);
        }
    };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket(int sockfd = -1) : _sockfd(sockfd)
        {
        }
        // 创建套接字
        void CreateSocket() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL, "sockfd create error\n");
                exit(SOCKET_ERROR);
            }
            LOG(INFO, "sockfd create success, sockfd is: %d\n", _sockfd);
        }
        // 绑定
        void CreateBind(uint16_t port) override
        {
            struct sockaddr_in local;           // 定义存储ip端口等信息的结构体
            memset(&local, 0, sizeof(0));       // 初始化
            local.sin_family = AF_INET;         // 网络通信
            local.sin_port = htons(port);       // 将端口转为网络序列
            local.sin_addr.s_addr = INADDR_ANY; // 服务端绑定任意 ip

            if (::bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                LOG(FATAL, "bind error\n");
                exit(BIND_ERROR);
            }
            LOG(INFO, "bind success\n");
        }
        // 监听
        void CreateListen(int blcklog = g_blcklog) override
        {
            if (::listen(_sockfd, blcklog) < 0)
            {
                LOG(FATAL, "listen error\n");
            }
            LOG(INFO, "listen success\n");
        }
        // 连接
        SockSPtr Accepter(Inet_Addr *client) override // 这里带上 Inet_Addr 的目的是方便打印
        {
            struct sockaddr_in clientaddr;
            socklen_t len = sizeof(clientaddr);
            int sock = ::accept(_sockfd, (struct sockaddr *)&clientaddr, &len);
            if (sock < 0)
            {
                LOG(FATAL, "accept error");
                return nullptr;
            }
            *client = Inet_Addr(clientaddr);
            LOG(FATAL, "get a new link, client info: %s sockfd is %d\n", client->AddrStr().c_str(), sock);
            return std::make_shared<TcpSocket>(sock); // C++14
        }
        // 获取连接
        bool Connector(std::string server_ip, uint16_t server_port) override
        {
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;                             // 网络通信
            server.sin_port = htons(server_port);                    // 主机端口的序列转为网络序列
            inet_pton(AF_INET, server_ip.c_str(), &server.sin_addr); // 将端口号设置为网络序列

            int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
            if (n < 0)
            {
                return false;
            }
            return true;
        }
        // 获取 socket
        int Sockfd() override
        {
            return _sockfd;
        }
        // 关闭 socket
        void Close() override
        {
            if (_sockfd > 0)
                ::close(_sockfd);
        }
        // 发送消息
        ssize_t Recv(std::string *out) override
        {
            char buffer[4096];
            ssize_t n = ::recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            if(n > 0)
            {
                buffer[n] = 0;
                *out = buffer;
            }
            return n;
        }
        // 接收消息
        ssize_t Send(const std::string &in) override
        {
            int n = ::send(_sockfd, in.c_str(), in.size(), 0);
            LOG(DEBUG, "n : %d\n", n);
            return n;
        }
        

    private:
        int _sockfd; // 既可以是 listensockfd 也可以是 IO sockfd
    };

    // class UdpServer : public Socket
    // {

    // };
} // namespace Socket_ns
